﻿#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PHMEE.Localization;

namespace PHMEE.EnergyEfficiency;

public class VoyageAppService : PHMEEAppService, IVoyageAppService
{
    private readonly VesselEeConfigDomainService _vesselEeConfigDomainService;
    private readonly ILogAbstractRepository _logAbstractRepository;
    private readonly ICiiReductionFactorRepository _ciiReductionFactorRepository;
    private readonly FuelConsumptionCalculator _fuelConsumptionCalculator;

    public VoyageAppService(VesselEeConfigDomainService vesselEeConfigDomainService,
        ILogAbstractRepository logAbstractRepository,
        ICiiReductionFactorRepository ciiReductionFactorRepository,
        FuelConsumptionCalculator fuelConsumptionCalculator)
    {
        LocalizationResource = typeof(EnergyEfficiencyResource);
        
        _vesselEeConfigDomainService = vesselEeConfigDomainService;
        _logAbstractRepository = logAbstractRepository;
        _ciiReductionFactorRepository = ciiReductionFactorRepository;
        _fuelConsumptionCalculator = fuelConsumptionCalculator;
    }
    
    /// <inheritdoc />
    public async Task<List<VoyageDto>> GetVoyagesAsync(Guid vesselId, DateTime startDate, DateTime endDate)
    {
        var vesselEeConfig = await _vesselEeConfigDomainService.GetOrDefaultByVesselIdAsync(vesselId);
        if (vesselEeConfig == null)
        {
            return [];
        }
        
        var (startDateTime, endDateTime) = QueryDateTimeUtils.ProcessForDateRangeQuery(startDate, endDate);
     
        // 时间段内的 Log Abstracts
        var logAbstracts = await _logAbstractRepository.GetListOpenClosedAsync(vesselId, startDateTime, endDateTime);
        
        // 获取完整的航次
        var voyages = LogAbstractDomainService.GetCompleteVoyages(logAbstracts);

        List<VoyageDto> result = new(voyages.Count);
        
        foreach (var voyage in voyages)
        {
            if (voyage.StartDepartureLogAbstract is null)
            {
                continue;
            }
            
            var startDeparture = voyage.StartDepartureLogAbstract;

            var voyageDto = new VoyageDto
            {
                VoyageNumber = startDeparture.VoyageNumber,
                VoyageFrom = startDeparture.VoyageFrom,
                VoyageTo = startDeparture.VoyageTo,
                StartTime = voyage.StartTime,
                EndTime = voyage.EndTime,
                IsSTS = voyage.IsSTS
            };
            
            result.Add(voyageDto);
        }
        
        return result;
    }

    /// <inheritdoc />
    public async Task<List<VoyageEEInfoDto>> GetVoyagesEEInfoAsync(Guid vesselId, DateTime startDate, DateTime endDate)
    {
        var vesselEeConfig = await _vesselEeConfigDomainService.GetOrDefaultByVesselIdAsync(vesselId);
        if (vesselEeConfig == null)
        {
            return [];
        }
        
        var z = await _ciiReductionFactorRepository.GetByYearAsync(startDate.Year);
        if (z is null)
        {
            return [];
        }
        
        var capacity = VesselEeConfigDomainService.GetCapacity(vesselEeConfig.VesselType, vesselEeConfig.DWT,
            vesselEeConfig.GT);
        
        var (startDateTime, endDateTime) = QueryDateTimeUtils.ProcessForDateRangeQuery(startDate, endDate);
     
        // 时间段内的 Log Abstracts
        var logAbstracts = await _logAbstractRepository.GetListOpenClosedAsync(vesselId, startDateTime, endDateTime);
        
        // 获取完整的航次
        var voyages = LogAbstractDomainService.GetCompleteVoyages(logAbstracts);
        
        List<VoyageEEInfoDto> result = new(voyages.Count);
        
        foreach (var voyage in voyages)
        {
            if (voyage.StartDepartureLogAbstract is null)
            {
                continue;
            }

            // 航次航程
            var distance = voyage.LogAbstracts.Sum(la => la.Distance);
            // EEOI
            var eeoi = LogAbstractFormulas.EEOINullable(voyage.LogAbstracts, vesselEeConfig.FuelTypes, vesselEeConfig.VesselType);
            // CII
            var cii = LogAbstractFormulas.CIINullable(voyage.LogAbstracts, capacity, vesselEeConfig.FuelTypes);
            CIIGrade? ciiGrade = cii is null
                ? null
                : CIIService.DetermineCIIGrade(cii.Value, vesselEeConfig.VesselType, vesselEeConfig.DWT, vesselEeConfig.GT,
                    z.Z);
            var ciiWithGrade = new CIIWithGradeDto(cii, ciiGrade);
            
            DateTime voyageStartTime = voyage.StartTime;
            DateTime voyageEndTime = voyage.EndTime;
            
            // 油品油耗
            var fuelMeasurements = new List<FuelMeasurement>();
            
            Dictionary<FuelType, float> fuelConsumptions =
                await _fuelConsumptionCalculator.GetFuelConsumptionForDateTimePeriodAsync(vesselId, voyageStartTime, voyageEndTime);
            
            foreach (FuelType fuelType in vesselEeConfig.FuelTypes)
            {
                if (fuelConsumptions.TryGetValue(fuelType, out var consumption))
                {
                    fuelMeasurements.Add(new FuelMeasurement(fuelType, consumption));
                }
                else
                {
                    fuelMeasurements.Add(new FuelMeasurement(fuelType, 0));
                }
            }
            
            var startDeparture = voyage.StartDepartureLogAbstract;
            var endDeparture = voyage.EndDepartureLogAbstract;

            var voyageDto = new VoyageEEInfoDto(endDeparture?.VoyageNumber ?? "", 
                startDeparture.VoyageFrom, 
                startDeparture.VoyageTo, 
                voyage.StartTime, 
                voyage.EndTime, 
                voyage.IsSTS, distance, eeoi, ciiWithGrade, fuelMeasurements);
            
            result.Add(voyageDto);
        }

        return result;
    }
}